#include "bsp_i2c.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <stdio.h>
#include "esp_log.h"
/* IDF v5.3.2  2024.12.6 i2c使用新的驱动,旧驱动过期 */
#define TAG "bsp_i2c"

#if CONFIG_USE_OLD_I2C_DRIVER == 0
i2c_master_dev_handle_t i2c_pca9557;
i2c_master_bus_handle_t i2c_handle;

i2c_master_bus_config_t i2c_bus_config = {
    .clk_source = I2C_CLK_SRC_DEFAULT,
    .i2c_port = -1,
    .scl_io_num = SCL_IO_PIN,
    .sda_io_num = SDA_IO_PIN,
    .flags.enable_internal_pullup = 1,
    .glitch_ignore_cnt = 7,

};

// io 扩展 pca9557
i2c_device_config_t i2c_pca9557_config = {
    .dev_addr_length = I2C_ADDR_BIT_LEN_7,
    .device_address = PCA9557_ADDR,
    .scl_speed_hz = MASTER_FREQUENCY,
    .flags.disable_ack_check = 0,
};
/***************    IO扩展芯片 ↓   *************************/

// 读取PCA9557寄存器的值
esp_err_t pca9557_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
{
    // return i2c_master_write_read_device(BSP_I2C_NUM, PCA9557_SENSOR_ADDR,  &reg_addr, 1, data, len, 1000 / portTICK_PERIOD_MS);
    return i2c_master_receive(i2c_pca9557, data, len, 2000);
}

// 给PCA9557的寄存器写值
esp_err_t pca9557_register_write_byte(uint8_t reg_addr, uint8_t data)
{
    esp_err_t ret = ESP_OK;
    uint8_t write_buf[2] = {reg_addr, data};
    // i2c_master_write_to_device(0, 0x19, write_buf, sizeof(write_buf), 1000);
    // i2c_master_transmit(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, int xfer_timeout_ms)
    ret = i2c_master_transmit(i2c_pca9557, write_buf, 2, 2000);
    // ESP_ERROR_CHECK(ret);
    return ret;
}

// new i2c driver sine 5.2.0
esp_err_t i2c_master_init()
{
    esp_err_t ret = ESP_OK;

    ret = i2c_new_master_bus(&i2c_bus_config, &i2c_handle);
    ESP_ERROR_CHECK(ret);
    // get i2c_pca9557
    ret = i2c_master_bus_add_device(i2c_handle, &i2c_pca9557_config, &i2c_pca9557);
    //  ESP_LOGI("I2C","slave_addr:0x%x",i2c_pca9557->device_address);
    ESP_ERROR_CHECK(ret);
    return ret;
}
#else

esp_err_t bsp_i2c_init(void)
{
    i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = SDA_IO_PIN,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_io_num = SCL_IO_PIN,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = MASTER_FREQUENCY,
    };
    i2c_param_config(I2C_PORT, &i2c_conf);

    return i2c_driver_install(I2C_PORT, i2c_conf.mode, 0, 0, 0);
}

// 读取PCA9557寄存器的值
esp_err_t pca9557_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
{
    return i2c_master_write_read_device(I2C_PORT, PCA9557_ADDR, &reg_addr, 1, data, len, 1000 / portTICK_PERIOD_MS);
}

// 给PCA9557的寄存器写值
esp_err_t pca9557_register_write_byte(uint8_t reg_addr, uint8_t data)
{
    uint8_t write_buf[2] = {reg_addr, data};

    return i2c_master_write_to_device(I2C_PORT, PCA9557_ADDR, write_buf, sizeof(write_buf), 1000 / portTICK_PERIOD_MS);
}

#endif
// 初始化PCA9557 IO扩展芯片
void pca9557_init(void)
{
    // 写入控制引脚默认值 DVP_PWDN=1  PA_EN = 0  LCD_CS = 1
    pca9557_register_write_byte(PCA9557_OUTPUT_PORT, 0x05);
    uint8_t io[2];
    pca9557_register_read(0, io, 1);
    ESP_LOGI(TAG, "io=%x", io[0]);
    // 把PCA9557芯片的IO1 IO1 IO2设置为输出 其它引脚保持默认的输入
    pca9557_register_write_byte(PCA9557_CONFIGURATION_PORT, 0xf8);
}

void i2c_init(void)
{
#if CONFIG_USE_OLD_I2C_DRIVER
    bsp_i2c_init();
#else
    i2c_master_init();
#endif
}

#define LCD_CS_GPIO                 BIT(0)    // PCA9557_GPIO_NUM_1
#define PA_EN_GPIO                  BIT(1)    // PCA9557_GPIO_NUM_2
#define DVP_PWDN_GPIO               BIT(2)    // PCA9557_GPIO_NUM_3

// 设置PCA9557芯片的某个IO引脚输出高低电平
esp_err_t pca9557_set_output_state(uint8_t gpio_bit, uint8_t level)
{
    uint8_t data;
    esp_err_t res = ESP_FAIL;

    pca9557_register_read(PCA9557_OUTPUT_PORT, &data, 1);
    res = pca9557_register_write_byte(PCA9557_OUTPUT_PORT, SET_BITS(data, gpio_bit, level));

    return res;
}

// 控制 PCA9557_LCD_CS 引脚输出高低电平 参数0输出低电平 参数1输出高电平 
void lcd_cs(uint8_t level)
{
    pca9557_set_output_state(LCD_CS_GPIO, level);
}

// 控制 PCA9557_PA_EN 引脚输出高低电平 参数0输出低电平 参数1输出高电平 
void pa_en(uint8_t level)
{
    pca9557_set_output_state(PA_EN_GPIO, level);
}

// 控制 PCA9557_DVP_PWDN 引脚输出高低电平 参数0输出低电平 参数1输出高电平 
void dvp_pwdn(uint8_t level)
{
    pca9557_set_output_state(DVP_PWDN_GPIO, level);
}
